#include"Channel.h"
#include"assert.h"
#include<string>
#include <sstream>
using namespace std;
namespace wjc {
	Channel::Channel(Core* core, int fd):
		core_(core),
		fd_(fd),
		events_(kNoneEvent),
		state_(State::kNew),
		isTied_(false),
		eventHandling_(false)
	{
	}
	Channel::~Channel() {
		assert(!eventHandling_);
		assert(!addedToLoop_);

		if (core_->isInCoreThread())
		{
			assert(!core_->hasChannel(this));
		}
	}

	//void Channel::destruction() {
	//	if (core_->isInCoreThread()) {
	//		disableAll();
	//		remove();
	//	}
	//	else {
	//		//core_->runInCore(Channel::destruction(),)
	//	}
	//}

	void Channel::handleEvent(Timestamp receiveTime) {
		std::shared_ptr<void> guard;
		if (isTied_) {
			guard = tie_.lock();
			if (!guard) return;
		}

		eventHandling_ = true;
		if ((revents_ & POLLHUP) && !(revents_ & POLLIN))
		{
			if (closeCallback_) closeCallback_();
		}
		if (revents_ & kReadEvent) {
			if (readCallback_) readCallback_(receiveTime);
		}
		if (revents_ & kWriteEvent) {
			if (writeCallback_) writeCallback_();
		}
		if (revents_ & kErrorEvent) {
			if (errorCallback_) errorCallback_();
		}
		eventHandling_ = false;
	}

	bool Channel::update() {
		addedToLoop_ = true;
		core_->updateChannel(this);
		return true;
	}

	void Channel::remove()
	{
		if (addedToLoop_) {
			addedToLoop_ = false;
			core_->removeChannel(this);
		}
	}

	string Channel::reventsToString() const
	{
		return eventsToString(fd_, revents_);
	}

	string Channel::eventsToString() const
	{
		return eventsToString(fd_, events_);
	}

	string Channel::eventsToString(int fd, int ev)
	{
		std::ostringstream oss;
		oss << fd << ": ";
		if (ev & POLLIN)
			oss << "IN ";
		if (ev & POLLPRI)
			oss << "PRI ";
		if (ev & POLLOUT)
			oss << "OUT ";
		if (ev & POLLHUP)
			oss << "HUP ";
		if (ev & POLLRDHUP)
			oss << "RDHUP ";
		if (ev & POLLERR)
			oss << "ERR ";
		if (ev & POLLNVAL)
			oss << "NVAL ";

		return oss.str();
	}
}